library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use WORK.COMMON.ALL;

-- 顶层模块
entity project is
port (
	CLK_100, CLK_11, CLK_KEY, RESET_KEY: in std_logic;
	PS2_DATA, PS2_CLK: in std_logic; -- PS2 clk and data
	HS, VS: out std_logic; --行同步、场同步信号
	oRed : out std_logic_vector (2 downto 0);
	oGreen : out std_logic_vector (2 downto 0);
	oBlue : out std_logic_vector (2 downto 0);
	
	NOW_PLAYER: out std_logic; -- A47
	NOW_CUT: out std_logic; -- A40
	NOW_TRUNKS: out ITrunkList;
	NOW_HP: out std_logic_vector(9 downto 0); -- A0 ~ A9
	NOW_SCORE: out std_logic_vector(9 downto 0); -- A25,A26,A39 ~ A32
	NOW_TIMER: out std_logic_vector(31 downto 0); -- A16 ~ A23
	R_KEY, L_ARROW, R_ARROW: out std_logic; -- A55 ~ A53
	CMD_OUT: out std_logic -- A52
);
end project;

architecture project_bhv of project is

component PS2 is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	PS2_DATA, PS2_CLK: in std_logic; -- PS2 clk and data
	SCANCODE: out std_logic_vector(7 downto 0); -- scan code signal output, 每接收到一组数据即输出
	OE: out std_logic -- 输出使能，每次输出的时候置1，无输出时置0
);
end component;

component Keyboard is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	PS2_CODE: in std_logic_vector(7 downto 0);
	PS2_OE: in std_logic;
	JUDGE_E: in std_logic;
	R_KEY, L_ARROW, R_ARROW: out std_logic -- 三个键输出使能，每次按下之后只在CLK_MAIN的一个周期内置1
);
end component;

component Judge is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	R_KEY, L_ARROW, R_ARROW: in std_logic;
	NOW_PLAYER: in std_logic;
	NOW_CUT: in std_logic;
	NOW_TRUNKS: in ITrunkList;
	NOW_HP: in std_logic_vector(9 downto 0);
	NOW_SCORE: in std_logic_vector(9 downto 0);
	NOW_TIMER: in std_logic_vector(31 downto 0);
	TRUNK_E: out std_logic; -- 生成树干使能
	JUDGE_E: out std_logic;
	CMD: out std_logic_vector(3 downto 0) -- 命令
);
end component;

component GenTrunk is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	E: in std_logic; -- 生成使能，1有效
	CMD_RESTART: in std_logic;
	NEW_TRUNK: out ITrunk -- 生成的树干，当E为0时输出无效
);
end component;

component Core is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	CMD: in std_logic_vector(3 downto 0);
	NEW_TRUNK: in ITrunk;
	NOW_PLAYER: in std_logic;
	NOW_CUT: in std_logic;
	NOW_TRUNKS: in ITrunkList;
	NOW_HP: in std_logic_vector(9 downto 0);
	NOW_SCORE: in std_logic_vector(9 downto 0);
	NOW_TIMER: in std_logic_vector(31 downto 0);
	NEW_PLAYER: out std_logic;
	NEW_CUT: out std_logic;
	NEW_TRUNKS: out ITrunkList;
	NEW_HP: out std_logic_vector(9 downto 0);
	NEW_SCORE: out std_logic_vector(9 downto 0);
	NEW_TIMER: out std_logic_vector(31 downto 0)
);
end component;

component Status is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	NEW_PLAYER: in std_logic; -- 玩家位置
	NEW_CUT: in std_logic;
	NEW_TRUNKS: in ITrunkList; -- 树干数组，下标0表示最下面的树干
	NEW_HP: in std_logic_vector(9 downto 0); -- 血条
	NEW_SCORE: in std_logic_vector(9 downto 0);
	NEW_TIMER: in std_logic_vector(31 downto 0); -- 时间
	NOW_PLAYER: out std_logic;
	NOW_CUT: out std_logic;
	NOW_TRUNKS: out ITrunkList;
	NOW_HP: out std_logic_vector(9 downto 0);
	NOW_SCORE: out std_logic_vector(9 downto 0);
	NOW_TIMER: out std_logic_vector(31 downto 0)
);
end component;

component Status2VGA is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	NOW_PLAYER: in std_logic;
	NOW_CUT: in std_logic;
	NOW_TRUNKS: in ITrunkList;
	NOW_HP: in std_logic_vector(9 downto 0);
	NOW_SCORE: in std_logic_vector(9 downto 0);
	NOW_TIMER: in std_logic_vector(31 downto 0);
	HS, VS: out std_logic; --行同步、场同步信号
	oRed : out std_logic_vector (2 downto 0);
	oGreen : out std_logic_vector (2 downto 0);
	oBlue : out std_logic_vector (2 downto 0)
);
end component;

	signal CLK_MAIN, CLK_25, CLK_50, RST: std_logic;
	signal PS2_CODE_TMP: std_logic_vector(7 downto 0);
	signal PS2_OE_TMP: std_logic;
	signal R_KEY_TMP, L_ARROW_TMP, R_ARROW_TMP: std_logic;
	signal NOW_PLAYER_TMP: std_logic;
	signal NOW_CUT_TMP: std_logic;
	signal NOW_TRUNKS_TMP: ITrunkList;
	signal NOW_HP_TMP: std_logic_vector(9 downto 0);
	signal NOW_SCORE_TMP: std_logic_vector(9 downto 0);
	signal NOW_TIMER_TMP: std_logic_vector(31 downto 0);
	signal NEW_PLAYER_TMP: std_logic;
	signal NEW_CUT_TMP: std_logic;
	signal NEW_TRUNKS_TMP: ITrunkList;
	signal NEW_HP_TMP: std_logic_vector(9 downto 0);
	signal NEW_SCORE_TMP: std_logic_vector(9 downto 0);
	signal NEW_TIMER_TMP: std_logic_vector(31 downto 0);
	signal EMPTY_OUT_TMP: std_logic;
	signal TRUNK_E_TMP: std_logic;
	signal JUDGE_E_TMP: std_logic;
	signal CMD_TMP: std_logic_vector(3 downto 0);
	signal CMD_RESTART_TMP: std_logic;
	signal NEW_TRUNK_TMP: ITrunk;
	
	signal CLK_PART: std_logic_vector(27 downto 0);

begin

	CLK_PART <= CLK_PART + 1 when rising_edge(CLK_100);
	CLK_MAIN <= CLK_PART(15); -- 1000HZ
	
	RST <= not RESET_KEY;
	CLK_50 <= not CLK_50 when rising_edge(CLK_100);
	CLK_25 <= not CLK_25 when rising_edge(CLK_50);
	
	NOW_PLAYER <= NOW_PLAYER_TMP;
	NOW_CUT <= NOW_CUT_TMP;
	NOW_TRUNKS <= NOW_TRUNKS_TMP;
	NOW_HP <= NOW_HP_TMP;
	NOW_SCORE <= NOW_SCORE_TMP;
	NOW_TIMER <= NOW_TIMER_TMP;
	R_KEY <= R_KEY_TMP;
	L_ARROW <= L_ARROW_TMP;
	R_ARROW <= R_ARROW_TMP;
	CMD_OUT <= '1' when CMD_TMP = CMD_RESTART else '0';
	CMD_RESTART_TMP <= '1' when CMD_TMP = CMD_RESTART else '0';

	ps2_i: PS2 port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		PS2_DATA=>PS2_DATA,
		PS2_CLK=>PS2_CLK,
		SCANCODE=>PS2_CODE_TMP,
		OE=>PS2_OE_TMP
	);
	
	keyboard_i: Keyboard port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		PS2_CODE=>PS2_CODE_TMP,
		PS2_OE=>PS2_OE_TMP,
		JUDGE_E=>JUDGE_E_TMP,
		R_KEY=>R_KEY_TMP,
		L_ARROW=>L_ARROW_TMP,
		R_ARROW=>R_ARROW_TMP
	);
	
	judge_i: Judge port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		R_KEY=>R_KEY_TMP,
		L_ARROW=>L_ARROW_TMP,
		R_ARROW=>R_ARROW_TMP,
		NOW_PLAYER=>NOW_PLAYER_TMP,
		NOW_CUT=>NOW_CUT_TMP,
		NOW_TRUNKS=>NOW_TRUNKS_TMP,
		NOW_HP=>NOW_HP_TMP,
		NOW_SCORE=>NOW_SCORE_TMP,
		NOW_TIMER=>NOW_TIMER_TMP,
		TRUNK_E=>TRUNK_E_TMP,
		JUDGE_E=>JUDGE_E_TMP,
		CMD=>CMD_TMP
	);
	
	trunk_i: GenTrunk port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		E=>TRUNK_E_TMP,
		CMD_RESTART=>CMD_RESTART_TMP,
		NEW_TRUNK=>NEW_TRUNK_TMP
	);
	
	core_i: Core port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		CMD=>CMD_TMP,
		NEW_TRUNK=>NEW_TRUNK_TMP,
		NOW_PLAYER=>NOW_PLAYER_TMP,
		NOW_CUT=>NOW_CUT_TMP,
		NOW_TRUNKS=>NOW_TRUNKS_TMP,
		NOW_HP=>NOW_HP_TMP,
		NOW_SCORE=>NOW_SCORE_TMP,
		NOW_TIMER=>NOW_TIMER_TMP,
		NEW_PLAYER=>NEW_PLAYER_TMP,
		NEW_CUT=>NEW_CUT_TMP,
		NEW_TRUNKS=>NEW_TRUNKS_TMP,
		NEW_HP=>NEW_HP_TMP,
		NEW_SCORE=>NEW_SCORE_TMP,
		NEW_TIMER=>NEW_TIMER_TMP
	);
	
	status_i: Status port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		NEW_PLAYER=>NEW_PLAYER_TMP,
		NEW_CUT=>NEW_CUT_TMP,
		NEW_TRUNKS=>NEW_TRUNKS_TMP,
		NEW_HP=>NEW_HP_TMP,
		NEW_SCORE=>NEW_SCORE_TMP,
		NEW_TIMER=>NEW_TIMER_TMP,
		NOW_PLAYER=>NOW_PLAYER_TMP,
		NOW_CUT=>NOW_CUT_TMP,
		NOW_TRUNKS=>NOW_TRUNKS_TMP,
		NOW_HP=>NOW_HP_TMP,
		NOW_SCORE=>NOW_SCORE_TMP,
		NOW_TIMER=>NOW_TIMER_TMP
	);
	
	status_2_vga_i: Status2VGA port map(
		CLK_MAIN=>CLK_MAIN,
		CLK_11=>CLK_11,
		CLK_25=>CLK_25,
		CLK_100=>CLK_100,
		RST=>RST,
		NOW_PLAYER=>NOW_PLAYER_TMP,
		NOW_CUT=>NOW_CUT_TMP,
		NOW_TRUNKS=>NOW_TRUNKS_TMP,
		NOW_HP=>NOW_HP_TMP,
		NOW_SCORE=>NOW_SCORE_TMP,
		NOW_TIMER=>NOW_TIMER_TMP,
		HS=>HS, VS=>VS,
		oRed=>oRed,
		oGreen=>oGreen,
		oBlue=>oBlue
	);

end project_bhv;
